using System;
using System.Drawing;
using System.Collections;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Configuration;
using System.IO;
using System.Windows.Forms;
using ActiproSoftware.Drawing;
using ActiproSoftware.SyntaxEditor;

namespace WindowsUserControl.Codes {

	/// <summary>
	/// Represents a Spell Check form.
	/// </summary>
	internal class SpellCheckForm : Form {

		//
		// NOTE TO DEVELOPERS
		// Search through this Form's source code for NOTE to see where to place code to integrate with your spell checker.
		//

		private bool				cancel;
		private SyntaxEditor		editor;
		private int					misspelledWordCount;
		private bool				replace;
		private	TextStream			stream;

		//

		private System.Windows.Forms.Button closeButton;
		private System.Windows.Forms.TextBox notFoundTextBox;
		private System.Windows.Forms.Button ignoreOnceButton;
		private System.Windows.Forms.Button ignoreAllButton;
		private System.Windows.Forms.Button addToDictionaryButton;
		private System.Windows.Forms.Button changeButton;
		private System.Windows.Forms.Button changeAllButton;
		private System.Windows.Forms.ListBox suggestionsListBox;
		private System.Windows.Forms.Label suggestionsCaptionLabel;
		private System.Windows.Forms.Label notFoundCaptionLabel;
		/// <summary>
		/// Required designer variable.
		/// </summary>
		private System.ComponentModel.Container components = null;

		/////////////////////////////////////////////////////////////////////////////////////////////////////
		// OBJECT
		/////////////////////////////////////////////////////////////////////////////////////////////////////

		/// <summary>
		/// Initializes a new instance of the <c>SpellCheckForm</c> class.
		/// </summary>
		/// <param name="editor">The <see cref="SyntaxEditor"/> that owns the dialog.</param>
		public SpellCheckForm(SyntaxEditor editor) {
			// Initialize parameters
			this.editor = editor;

			//
			// Required for Windows Form Designer support
			//
			InitializeComponent();
		}

		/// <summary>
		/// Releases the unmanaged resources used by the Control and optionally releases the managed resources.
		/// </summary>
		/// <param name="disposing">
		/// <c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources. 
		/// </param>
		protected override void Dispose(bool disposing) {
			if (disposing) {
				if(components != null)
					components.Dispose();
			}
			base.Dispose(disposing);
		}

		#region Windows Form Designer generated code
		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{
			this.notFoundCaptionLabel = new System.Windows.Forms.Label();
			this.notFoundTextBox = new System.Windows.Forms.TextBox();
			this.suggestionsCaptionLabel = new System.Windows.Forms.Label();
			this.ignoreOnceButton = new System.Windows.Forms.Button();
			this.ignoreAllButton = new System.Windows.Forms.Button();
			this.addToDictionaryButton = new System.Windows.Forms.Button();
			this.closeButton = new System.Windows.Forms.Button();
			this.changeButton = new System.Windows.Forms.Button();
			this.changeAllButton = new System.Windows.Forms.Button();
			this.suggestionsListBox = new System.Windows.Forms.ListBox();
			this.SuspendLayout();
			// 
			// notFoundCaptionLabel
			// 
			this.notFoundCaptionLabel.Location = new System.Drawing.Point(4, 16);
			this.notFoundCaptionLabel.Name = "notFoundCaptionLabel";
			this.notFoundCaptionLabel.Size = new System.Drawing.Size(84, 12);
			this.notFoundCaptionLabel.TabIndex = 0;
			this.notFoundCaptionLabel.Text = "Not Found";
			this.notFoundCaptionLabel.TextAlign = System.Drawing.ContentAlignment.TopRight;
			// 
			// notFoundTextBox
			// 
			this.notFoundTextBox.Location = new System.Drawing.Point(92, 12);
			this.notFoundTextBox.Name = "notFoundTextBox";
			this.notFoundTextBox.ReadOnly = true;
			this.notFoundTextBox.Size = new System.Drawing.Size(240, 20);
			this.notFoundTextBox.TabIndex = 0;
			this.notFoundTextBox.Text = "";
			// 
			// suggestionsCaptionLabel
			// 
			this.suggestionsCaptionLabel.Location = new System.Drawing.Point(4, 42);
			this.suggestionsCaptionLabel.Name = "suggestionsCaptionLabel";
			this.suggestionsCaptionLabel.Size = new System.Drawing.Size(84, 22);
			this.suggestionsCaptionLabel.TabIndex = 2;
			this.suggestionsCaptionLabel.Text = "Suggestions";
			this.suggestionsCaptionLabel.TextAlign = System.Drawing.ContentAlignment.TopRight;
			// 
			// ignoreOnceButton
			// 
			this.ignoreOnceButton.FlatStyle = System.Windows.Forms.FlatStyle.System;
			this.ignoreOnceButton.Location = new System.Drawing.Point(340, 12);
			this.ignoreOnceButton.Name = "ignoreOnceButton";
			this.ignoreOnceButton.Size = new System.Drawing.Size(104, 23);
			this.ignoreOnceButton.TabIndex = 3;
			this.ignoreOnceButton.Text = "Ignore Once";
			this.ignoreOnceButton.Click += new System.EventHandler(this.ignoreOnceButton_Click);
			// 
			// ignoreAllButton
			// 
			this.ignoreAllButton.FlatStyle = System.Windows.Forms.FlatStyle.System;
			this.ignoreAllButton.Location = new System.Drawing.Point(340, 36);
			this.ignoreAllButton.Name = "ignoreAllButton";
			this.ignoreAllButton.Size = new System.Drawing.Size(104, 23);
			this.ignoreAllButton.TabIndex = 4;
			this.ignoreAllButton.Text = "Ignore All";
			this.ignoreAllButton.Click += new System.EventHandler(this.ignoreAllButton_Click);
			// 
			// addToDictionaryButton
			// 
			this.addToDictionaryButton.FlatStyle = System.Windows.Forms.FlatStyle.System;
			this.addToDictionaryButton.Location = new System.Drawing.Point(340, 60);
			this.addToDictionaryButton.Name = "addToDictionaryButton";
			this.addToDictionaryButton.Size = new System.Drawing.Size(104, 23);
			this.addToDictionaryButton.TabIndex = 5;
			this.addToDictionaryButton.Text = "Add to Dictionary";
			this.addToDictionaryButton.Click += new System.EventHandler(this.addToDictionaryButton_Click);
			// 
			// closeButton
			// 
			this.closeButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
			this.closeButton.FlatStyle = System.Windows.Forms.FlatStyle.System;
			this.closeButton.Location = new System.Drawing.Point(340, 148);
			this.closeButton.Name = "closeButton";
			this.closeButton.Size = new System.Drawing.Size(104, 23);
			this.closeButton.TabIndex = 6;
			this.closeButton.Text = "Close";
			this.closeButton.Click += new System.EventHandler(this.closeButton_Click);
			// 
			// changeButton
			// 
			this.changeButton.Enabled = false;
			this.changeButton.FlatStyle = System.Windows.Forms.FlatStyle.System;
			this.changeButton.Location = new System.Drawing.Point(340, 92);
			this.changeButton.Name = "changeButton";
			this.changeButton.Size = new System.Drawing.Size(104, 23);
			this.changeButton.TabIndex = 7;
			this.changeButton.Text = "Change";
			this.changeButton.Click += new System.EventHandler(this.changeButton_Click);
			// 
			// changeAllButton
			// 
			this.changeAllButton.Enabled = false;
			this.changeAllButton.FlatStyle = System.Windows.Forms.FlatStyle.System;
			this.changeAllButton.Location = new System.Drawing.Point(340, 116);
			this.changeAllButton.Name = "changeAllButton";
			this.changeAllButton.Size = new System.Drawing.Size(104, 23);
			this.changeAllButton.TabIndex = 8;
			this.changeAllButton.Text = "Change All";
			this.changeAllButton.Click += new System.EventHandler(this.changeAllButton_Click);
			// 
			// suggestionsListBox
			// 
			this.suggestionsListBox.Location = new System.Drawing.Point(92, 40);
			this.suggestionsListBox.Name = "suggestionsListBox";
			this.suggestionsListBox.Size = new System.Drawing.Size(240, 95);
			this.suggestionsListBox.TabIndex = 9;
			this.suggestionsListBox.SelectedIndexChanged += new System.EventHandler(this.suggestionsListBox_SelectedIndexChanged);
			// 
			// SpellCheckForm
			// 
			this.AcceptButton = this.ignoreOnceButton;
			this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
			this.CancelButton = this.closeButton;
			this.ClientSize = new System.Drawing.Size(454, 180);
			this.Controls.AddRange(new System.Windows.Forms.Control[] {
																		  this.suggestionsListBox,
																		  this.changeAllButton,
																		  this.changeButton,
																		  this.closeButton,
																		  this.addToDictionaryButton,
																		  this.ignoreAllButton,
																		  this.ignoreOnceButton,
																		  this.suggestionsCaptionLabel,
																		  this.notFoundTextBox,
																		  this.notFoundCaptionLabel});
			this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
			this.MaximizeBox = false;
			this.MinimizeBox = false;
			this.Name = "SpellCheckForm";
			this.ShowInTaskbar = false;
			this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
			this.Text = "Spell Check";
			this.ResumeLayout(false);

		}
		#endregion

		/////////////////////////////////////////////////////////////////////////////////////////////////////
		// EVENT HANDLERS
		/////////////////////////////////////////////////////////////////////////////////////////////////////

		/// <summary>
		/// Occurs when the button is clicked.
		/// </summary>
		/// <param name="sender">Sender of the event.</param>
		/// <param name="e">An <see cref="EventArgs"/> that contains data related to the event.</param>
		private void addToDictionaryButton_Click(object sender, System.EventArgs e) {
			//
			// NOTE: Add the word in the not found textbox to the custom dictionary of the spell checker here
			//

			// Hide the form
			this.Hide();
		}

		/// <summary>
		/// Occurs when the button is clicked.
		/// </summary>
		/// <param name="sender">Sender of the event.</param>
		/// <param name="e">An <see cref="EventArgs"/> that contains data related to the event.</param>
		private void changeAllButton_Click(object sender, System.EventArgs e) {
			//
			// NOTE: Add the word in the not found textbox to the ChangeAll collection of the spell checker here
			//

			// Mark to replace the word in the CheckSpelling procedure
			replace = true;

			// Hide the form
			this.Hide();
		}

		/// <summary>
		/// Occurs when the button is clicked.
		/// </summary>
		/// <param name="sender">Sender of the event.</param>
		/// <param name="e">An <see cref="EventArgs"/> that contains data related to the event.</param>
		private void changeButton_Click(object sender, System.EventArgs e) {
			// Mark to replace the word in the CheckSpelling procedure
			replace = true;

			// Hide the form
			this.Hide();
		}

		/// <summary>
		/// Occurs when the button is clicked.
		/// </summary>
		/// <param name="sender">Sender of the event.</param>
		/// <param name="e">An <see cref="EventArgs"/> that contains data related to the event.</param>
		private void closeButton_Click(object sender, System.EventArgs e) {
			// Mark to cancel the spell check
			cancel = true;

			// Hide the form
			this.Hide();
		}

		/// <summary>
		/// Occurs when the button is clicked.
		/// </summary>
		/// <param name="sender">Sender of the event.</param>
		/// <param name="e">An <see cref="EventArgs"/> that contains data related to the event.</param>
		private void ignoreAllButton_Click(object sender, System.EventArgs e) {
			//
			// NOTE: Add the word in the not found textbox to the IgnoreAll collection of the spell checker here
			//

			// Hide the form
			this.Hide();
		}

		/// <summary>
		/// Occurs when the button is clicked.
		/// </summary>
		/// <param name="sender">Sender of the event.</param>
		/// <param name="e">An <see cref="EventArgs"/> that contains data related to the event.</param>
		private void ignoreOnceButton_Click(object sender, System.EventArgs e) {
			// Hide the form
			this.Hide();
		}

		/// <summary>
		/// Occurs when the selected index is changed.
		/// </summary>
		/// <param name="sender">Sender of the event.</param>
		/// <param name="e">An <see cref="EventArgs"/> that contains data related to the event.</param>
		private void suggestionsListBox_SelectedIndexChanged(object sender, System.EventArgs e) {
			changeButton.Enabled = (suggestionsListBox.SelectedIndex != -1);
			changeAllButton.Enabled = changeButton.Enabled;
		}

		/////////////////////////////////////////////////////////////////////////////////////////////////////
		// NON-PUBLIC PROCEDURES
		/////////////////////////////////////////////////////////////////////////////////////////////////////

		/// <summary>
		/// Spell checks a word.
		/// </summary>
		/// <param name="word">The word to check.</param>
		/// <returns>
		/// If the word is found in the dictionary, it is returned.
		/// If a replacement word is to be used (via a ChangeAll setting), the replacement word is returned.
		/// If the word is not found in the dictionary, <c>null</c> is returned.
		/// </returns>
		private string CheckWord(string word) {
			//
			// NOTE: Use the spell checker to check the specified word here
			//

			return null;
		}

		/// <summary>
		/// Populates the list of suggestions for the specified word.
		/// </summary>
		/// <param name="word">The word to check.</param>
		private void PopulateSuggestionsForWord(string word) {
			// Clear the suggestions list
			suggestionsListBox.Items.Clear();

			//
			// NOTE: Remove sample code and use the spell checker to populate the suggestions list here
			//
			suggestionsListBox.Items.Add("Actipro");
			suggestionsListBox.Items.Add("Software");
			suggestionsListBox.Items.Add("SyntaxEditor");

			// Select the first item
			if (suggestionsListBox.Items.Count > 0)
				suggestionsListBox.SelectedIndex = 0;
		}

		/////////////////////////////////////////////////////////////////////////////////////////////////////
		// PUBLIC PROCEDURES
		/////////////////////////////////////////////////////////////////////////////////////////////////////

		/// <summary>
		/// Checks the spelling of the text in the editor.
		/// </summary>
		public void CheckSpelling() {
			//
			// NOTE: Remove this messagebox
			//
			MessageBox.Show("This spell check sample is a stub to show you how to implement spell checking with SyntaxEditor.  It requires the use of a third-party spell checking component.  The sample only checks words in comments and thinks every comment word is misspelled.  To use this form in your own application, simply include this form and add code where all the TODO sections are.  It's very easy to customize to any third-party spell checker to provide full spell checking capabilities in your application.", "Spell Check Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
			
			// Create a text stream
			stream = editor.Document.GetTextStream(0);

			// Reset the misspelled word count
			misspelledWordCount = 0;

			while (!stream.IsAtDocumentEnd) {
				// 
				// NOTE: Right now, it is only spell checking in comment words... change if necessary
				//
				switch (stream.Token.Key) {
					case "CommentWordToken":
					case "MultiLineCommentWordToken": {
						// Get the word to check 
						TextRange wordRange = editor.Document.GetWordTextRange(stream.Offset);
						string word = editor.Document.GetWordText(stream.Offset);

						// Check the spelling of the word
						string replacementWord = this.CheckWord(word);

						// If the word is not found or a replacement word is to be used...
						if (word != replacementWord) {
							// Increment the misspelled word count
							misspelledWordCount++;

							// If the word was not found...
							if (replacementWord == null) {
								// Select the word in the editor
								editor.SelectedView.Selection.SelectRange(wordRange);

								// Show the word in the not found textbox
								this.notFoundTextBox.Text = word;

								// Populate suggestions
								this.PopulateSuggestionsForWord(word);

								// Show the form
								cancel = false;
								replace = false;
								this.ShowDialog();

								// If a replace should occur, get the replacement word
								if (replace)
									replacementWord = suggestionsListBox.SelectedItem.ToString();
							}

							// If a replacement word has been set, replace the word with it
							if (replacementWord != null) {
								editor.Document.ReplaceText(DocumentModificationType.SpellingChange, wordRange.StartOffset, wordRange.Length, replacementWord);
								stream.SeekCharacter(replacementWord.Length - wordRange.Length);
							}
						}
						break;
					}
				}
		
				// Quit if cancelled
				if (cancel) {
					cancel = true;
					break;
				}

				// Goto the next word
				stream.GoToNextWordStart();
			}

			if (misspelledWordCount > 0)
				MessageBox.Show("Done spell checking.  " + misspelledWordCount + " spelling error(s).", "Spell Check Sample", MessageBoxButtons.OK, MessageBoxIcon.Information);
			else
				MessageBox.Show("Done spell checking.  No spelling errors.", "Spell Check Sample", MessageBoxButtons.OK, MessageBoxIcon.Information);
		}

	}
}
